package com.hong.spring.service.impl;

import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import com.hong.spring.dao.UserMapper;
import com.hong.spring.entity.User;
import com.hong.spring.entity.ao.UserAO;
import com.hong.spring.service.IUserService;
import com.hong.spring.utils.DataResponse;
import com.hong.spring.utils.RedisCacheManager;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * @Auther: csh
 * @Date: 2020/8/18 15:16
 * @Description:用户实现
 */
@Service
@Log4j2
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements IUserService  {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisCacheManager redisCacheManager;

    @Override
    public DataResponse<List<User>> findByAll() {
        List <User> allUserList = userMapper.selectList(null);
        Integer allTotal = userMapper.selectCount(null);
        return DataResponse.BuildSuccessResponse(allUserList,allTotal);
    }


    @Override
    public DataResponse <Boolean> insertBatch(List <User> list) {
        if(null==list){
            return DataResponse.BuildFailResponse("参数不能为空!");
        }
        boolean batchSave = this.saveBatch(list);
        return DataResponse.BuildSuccessResponse(batchSave);
    }

    @Transactional
    public DataResponse <Boolean> update(User user) {
        if(null==user || user.getId()==null){
            return DataResponse.BuildFailResponse("必传参数不能为空!");
        }
        int update = userMapper.update(user);
        return DataResponse.BuildSuccessResponse(update>0?true:false);
    }
    @Override
    @Cacheable(value = "findById",key="#id")
    public DataResponse <User> findById(int id) {
        log.info("进入数据库查询");
        User user = userMapper.findById(id);
        return DataResponse.BuildSuccessResponse(user);
    }

    @Override
    public DataResponse <User> findById2(Integer id) {
        //log.info("缓存击穿，进入数据库查询");
        if(null==id){
            return DataResponse.BuildFailResponse("必传参数不能为空!");
        }
        String name = Thread.currentThread().getName();
        String key  = "user2_" + id;
        String lockName=key+".lock";
        Boolean lock = redisCacheManager.setNx(lockName, lockName);
        int count=0;
        log.info("线程{}锁状态{}",name,lock);
        User user=null;
        try {
            //睡上100毫秒
            while (!lock && count<10){
                Thread.sleep(100);
                count++;
                log.info("线程{}第{}次获取锁",name,count);
                lock =redisCacheManager.setNx(lockName,lockName);
            }
            if(!lock && count==10){
                log.info("请求超过10次，做业务处理....");
                return DataResponse.BuildFailResponse("请求频繁，请重试!");
            }
            if(redisCacheManager.hasKey("user2_"+id)){
                log.info("线程{}查询缓存有值",name);
                String userStr = (String)redisCacheManager.get("user2_" + id);
                if(null!=userStr && !StringUtils.isEmpty(userStr)){
                    user = JSONObject.parseObject(userStr, User.class);
                }
            }
            if(null==user){
                log.info("线程{}开始锁！开始查询数据库",name);
                user = userMapper.findById(id);
                if(null!=user){
                    log.info("线程{}将值放到缓存中",name);
                    redisCacheManager.set("user2_"+id, JSONObject.toJSONString(user),3);
                }
            }
        }catch (Exception e){
            log.error("异常{}",e);
        }finally {
            log.info("线程{}解锁成功!",name);
            redisCacheManager.unLock(lockName);
        }
        return DataResponse.BuildSuccessResponse(user);
    }

    @Override
    public DataResponse <User> findById3(Integer id) throws InterruptedException {
        if(null==id){
            return DataResponse.BuildFailResponse("必传参数不能为空!");
        }

        User user;
        if(redisCacheManager.hasKey("user_" + id)){
            log.info("有缓存值...获取中");
            String userStr = (String)redisCacheManager.get("user_" + id);
            if(null!=userStr && !StringUtils.isEmpty(userStr)){
                user = JSONObject.parseObject(userStr, User.class);
                return DataResponse.BuildSuccessResponse(user);
            }
        }
        log.info("查询db中.....");
        user = userMapper.findById(id);
        Thread.sleep(100);
        if(null!=user){
            Integer random = Integer.valueOf(RandomStringUtils.randomNumeric(2));
            redisCacheManager.set("user_"+id, JSONObject.toJSONString(user),random);
        }

        return DataResponse.BuildSuccessResponse(user);
    }

    @Override
    public DataResponse <List <User>> findByPage(UserAO ao) {
        if(ao==null){
            ao.setPage(0);
            ao.setPageSize(10);
        }else{
            ao.setPage(ao.getPageSize() * ao.getPage());
        }
        int allTotal = userMapper.findAllTotal();
        List <User> byPage = userMapper.findByPage(ao);
        return DataResponse.BuildSuccessResponse(byPage,allTotal);
    }

    @Override
    @CacheEvict(value = "findById",key="#id")
    public void deleteCache(Integer id) {
        log.info("删除缓存成功!");
    }

    @Override
    @SentinelResource(value = "findById5",blockHandler  = "findById5Fallback")
    public DataResponse <User> handlerById(Integer id) {
        if(null==id){
            return DataResponse.BuildFailResponse("必传参数不能为空!");
        }
        User user;
        String userStr = (String)redisCacheManager.get("user_" + id);
        if(null==userStr || StringUtils.isEmpty(userStr)){
          user = userMapper.findById(id);
            if(null!=user){
                redisCacheManager.set("user_"+id, JSONObject.toJSONString(user));
            }
        }else{
            user = JSONObject.parseObject(userStr, User.class);
        }

        return DataResponse.BuildSuccessResponse(user);
    }

    public static DataResponse findById5Fallback(Integer id, BlockException ex){
        log.info("进入限流了!");
        return DataResponse.BuildFailResponse("访问高峰期请重试...");
    }
}
